package co.dreamapps.dodoattack.model;

import java.io.IOException;

import org.andengine.audio.sound.Sound;
import org.andengine.audio.sound.SoundFactory;
import org.andengine.engine.Engine;
import org.andengine.entity.IEntity;
import org.andengine.entity.modifier.JumpModifier;
import org.andengine.entity.modifier.IEntityModifier.IEntityModifierListener;
import org.andengine.entity.modifier.MoveModifier;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.sprite.AnimatedSprite;
import org.andengine.opengl.texture.TextureManager;
import org.andengine.opengl.texture.TextureOptions;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.opengl.texture.region.ITiledTextureRegion;
import org.andengine.opengl.vbo.VertexBufferObjectManager;
import org.andengine.util.modifier.IModifier;

import android.content.Context;
import android.util.Log;

public class Dodo {	

	/**
	 * Public constants
	 */
	public static final int SOUND_JUMP_SIMPLE = 0;
	public static final int SOUND_TURKEY = 1;
	public static final int SOUND_JUMP_DOUBLE = 2;

	/**
	 * Private constants
	 */
	private static final long[] DURATION_FRAME_NORMAL = { 100, 100, 150, 125, 100, 100 };
	private static final float JUMP_DURATION = 1;
	private static final float MOVING_ANIMATION_DURATION = 0.5f;
	private static final float MOVING_FACTOR = 25;

	/**
	 * Animation
	 */
	private ITiledTextureRegion texturaAnimada;
	private BitmapTextureAtlas atlasAnimacion;
	private AnimatedSprite spriteAnimado;

	/**
	 * Variables
	 */
	private int floor;
	private int windowWidth;
	private int jumpingTimes = 0;
	private int sentWhileNotMoving;

	/**
	 * Modifiers
	 */
	private JumpModifier jumpModifier;
	private MoveModifier moveModifier;

	/**
	 * Sound
	 */
	private Sound soundJumpSimple;
	private Sound soundJumpDoble;
	private Sound turkeySound;

	/**
	 * Connection
	 */
	private RoomManagerDodoGame roomManager;
	private boolean sendUpdates;

	/**
	 * Constructor
	 */
	public Dodo(RoomManagerDodoGame roomManager, int windowWidth, boolean sendUpdates) {
		this.roomManager = roomManager;
		this.windowWidth = windowWidth;
		this.sendUpdates = sendUpdates;
	}

	// ************************************* ANDENGINE *************************************

	public void onCreateResources(TextureManager textureManager, Engine engine, Context context) throws IOException {
		atlasAnimacion = new BitmapTextureAtlas(textureManager, 480, 344,TextureOptions.DEFAULT);
		texturaAnimada = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(atlasAnimacion, context,"dodoSecuencia.png", 0, 0, 3, 2);
		atlasAnimacion.load();
		try {
			soundJumpSimple = SoundFactory.createSoundFromAsset(engine.getSoundManager(), context, "sonido/jumpSimple.mp3");
			soundJumpSimple.setVolume(0.9F);
			soundJumpSimple.setLooping(false);
		} catch (IOException e) {
			Log.e("Alejo", "IOException: Carga de audio");
		}
		
		try {
			soundJumpDoble = SoundFactory.createSoundFromAsset(engine.getSoundManager(), context, "sonido/jumpDouble.mp3");
			soundJumpDoble.setLooping(false);
		} catch (IOException e) {
			Log.e("Alejo", "IOException: Carga de audio");
		}

		try {
			turkeySound = SoundFactory.createSoundFromAsset(engine.getSoundManager(), context, "sonido/turkeySound.mp3");
			turkeySound.setLooping(false);
		} catch (IOException e) {
			Log.e("Alejo", "IOException: Carga de audio");
		}
		
		
		
	}

	public void onCreateScene(VertexBufferObjectManager vertexBufferObjectManager, Scene scene, int x, int y) {
		this.floor = y;
		spriteAnimado = new AnimatedSprite(x, y, texturaAnimada, vertexBufferObjectManager);
		spriteAnimado.animate(DURATION_FRAME_NORMAL, 0, 5, true);
		scene.attachChild(spriteAnimado);
	}

	// ************************************* ANDENGINE *************************************

	public IEntity getEntity() {
		return spriteAnimado;
	}

	public void scream(int soundId) {
		switch (soundId) {
		case SOUND_JUMP_SIMPLE:
			soundJumpSimple.play();
			break;
		case SOUND_TURKEY:
			turkeySound.play();
			break;
		case SOUND_JUMP_DOUBLE:
			soundJumpDoble.play();
			break;
		}
	}

	// *********************************** LOCAL METHODS ***********************************

	public void jump() {
		if (jumpingTimes < 2) {
			scream(SOUND_JUMP_SIMPLE);
			jumpingTimes ++;
			if(sendUpdates) {
				roomManager.dodoJump(jumpingTimes, (int)spriteAnimado.getY(), 0, true);
			}
			if(jumpingTimes == 2)
			scream(SOUND_JUMP_DOUBLE);
			if(jumpModifier != null) {
				spriteAnimado.unregisterEntityModifier(jumpModifier);
				jumpModifier = null;
			}
			if(moveModifier != null) {
				spriteAnimado.unregisterEntityModifier(moveModifier);
				moveModifier = null;
			}
			jumpModifier = new JumpModifier(1, spriteAnimado.getX(), spriteAnimado.getX(), spriteAnimado.getY(), floor, -300, new IEntityModifierListener() {
				@Override
				public void onModifierStarted(
						IModifier<IEntity> pModifier, IEntity pItem) {
					if(jumpingTimes == 2) {
						long[] duracionFrame = { 60, 60, 60 };
						spriteAnimado.animate(duracionFrame, 2, 4, true);
					}
				}

				@Override
				public void onModifierFinished(
						IModifier<IEntity> pModifier, IEntity pItem) {
					jumpingTimes = 0;
					spriteAnimado.animate(DURATION_FRAME_NORMAL, 0, 5, true);
					jumpModifier = null;
				}
			});
			spriteAnimado.registerEntityModifier(jumpModifier);
			// Jumping Update Thread
			if(sendUpdates) {
				new Thread(new Runnable() {
					@Override
					public void run() {
						int jumpingIndex = jumpingTimes;
						int totalTime = 0;
						while(jumpingIndex == jumpingTimes) {
							if(totalTime > 0)
								roomManager.dodoJump(jumpingIndex, (int)spriteAnimado.getY(), totalTime, false);
							try {Thread.sleep(200);} catch (Exception e) {}
							totalTime += 200;
						}
					}
				}).start();
			}
		}
	}

	public void setHorizontalMove(float xGravity) {
		if(jumpModifier == null && Math.abs(xGravity) > 1) {
			sentWhileNotMoving = 0;
			float aimedPositionX = spriteAnimado.getX() + xGravity*MOVING_FACTOR;
			if(aimedPositionX < spriteAnimado.getWidth()) {
				aimedPositionX = spriteAnimado.getWidth();
			} else if(aimedPositionX > windowWidth - spriteAnimado.getWidth()) {
				aimedPositionX = windowWidth - spriteAnimado.getWidth();
			}
			if(aimedPositionX != spriteAnimado.getX()) {
				if(roomManager.dodoHorizontalMove((int) aimedPositionX)) {
					if(moveModifier != null) {
						spriteAnimado.unregisterEntityModifier(moveModifier);
					}
					moveModifier = new MoveModifier(MOVING_ANIMATION_DURATION, spriteAnimado.getX(), floor, aimedPositionX, floor);
					spriteAnimado.registerEntityModifier(moveModifier);
				}
			}
		} else if(sentWhileNotMoving < 3 && roomManager.dodoHorizontalMove((int) spriteAnimado.getX())) {
			sentWhileNotMoving ++;
		}
	}

	// *********************************** LOCAL METHODS ***********************************

	// *********************************** REMOTE METHODS **********************************

	public void jump(int jumpingTimesReceived, int actualY, int time) {
		if(jumpingTimesReceived > jumpingTimes) {
			scream(SOUND_JUMP_SIMPLE);			
			if(jumpingTimesReceived ==2){
				scream(SOUND_JUMP_DOUBLE);
			}
			jumpingTimes = jumpingTimesReceived;
			if(jumpModifier != null) {
				spriteAnimado.unregisterEntityModifier(jumpModifier);
				jumpModifier = null;
			}
			if(moveModifier != null) {
				spriteAnimado.unregisterEntityModifier(moveModifier);
				moveModifier = null;
			}
			float jumpingTime = ((float)(JUMP_DURATION*1000 - time))/(JUMP_DURATION*1000);
			if(jumpingTime > 0) {
				float jumpHeight = time == 0 ? - 300 : spriteAnimado.getY() - floor - 300;
				jumpModifier = new JumpModifier(jumpingTime, spriteAnimado.getX(), spriteAnimado.getX(), spriteAnimado.getY(), floor, jumpHeight, new IEntityModifierListener() {
					@Override
					public void onModifierStarted(
							IModifier<IEntity> pModifier, IEntity pItem) {
						if(jumpingTimes == 2) {
							long[] duracionFrame = { 60, 60, 60 };
							spriteAnimado.animate(duracionFrame, 2, 4, true);
						}
					}

					@Override
					public void onModifierFinished(
							IModifier<IEntity> pModifier, IEntity pItem) {
						jumpingTimes = 0;
						spriteAnimado.animate(DURATION_FRAME_NORMAL, 0, 5, true);
						jumpModifier = null;
					}
				});
				spriteAnimado.registerEntityModifier(jumpModifier);
			}
		}
	}

	public void setRemoteHorizontalMove(int aimedPositionX) {
		if(moveModifier != null) {
			spriteAnimado.unregisterEntityModifier(moveModifier);
		}
		moveModifier = new MoveModifier(MOVING_ANIMATION_DURATION, spriteAnimado.getX(), floor, aimedPositionX, floor);
		spriteAnimado.registerEntityModifier(moveModifier);
	}

	// *********************************** REMOTE METHODS **********************************

}
